#ifndef ViewAdaptor_H
#define ViewAdaptor_H

#include "simodo/shell/document/ViewAdaptor_interface.h"
#include "simodo/shell/document/Document_plugin.h"
#include "simodo/shell/document/ViewAdaptorLsp_interface.h"
#include "simodo/shell/document/ViewAdaptorFind_interface.h"
#include "simodo/shell/access/LspStructures.h"

#include "GeneralTextDocumentAdaptor.h"
#include "widget/CodeEdit.h"
#include "widget/Highlighter.h"

#include "simodo/variable/Variable.h"
// #include "simodo/inout/token/LexicalParameters.h"

#include <memory>

class GeneralTextPlugin;
class GeneralTextWidget;

QT_BEGIN_NAMESPACE
QT_END_NAMESPACE

namespace shell = simodo::shell;

class GeneralTextViewAdaptor : public QObject,
                        public shell::ViewAdaptor_interface,
                        public shell::ViewAdaptorLsp_interface,
                        public shell::ViewAdaptorFind_interface
{
    Q_OBJECT

    shell::Access_interface &           _shell;
    GeneralTextPlugin *                 _plugin;
    std::shared_ptr<shell::DocumentAdaptor_interface>  _document_adaptor;
    QString                             _path_to_file;
    HighlightData                       _highlight_data;
    // std::shared_ptr<simodo::inout::LexicalParameters> _lexis;
    CodeEdit *                          _editor = nullptr;
    CodeEdit *                          _current_editor = nullptr;
    GeneralTextWidget *                 _widget = nullptr;

    CodeEditParameters                  _edit_params;

    QList<QString>                      _lexis_symbols;
    QVector<shell::DocumentSymbol>      _symbols;
    QVector<shell::CompletionItem>      _completions;

    int     _version                    = 0;
    int     _lsp_change_delay_timer     = 0;
    int     _autosave_change_delay_timer= 0;

    /// \todo Эти суммы лучше хранить в документе (GeneralTextDocumentAdaptor).
    /// Тогда при повторном открытии не нужно будет перерисовывать.
    int     _publishDiagnostics_checksum = 0;
    int     _semanticTokens_checksum     = 0;

public:
    GeneralTextViewAdaptor(shell::Access_interface & shell_access, GeneralTextPlugin * plugin,
                           std::shared_ptr<shell::DocumentAdaptor_interface>, const QString & path_to_file);
    ~GeneralTextViewAdaptor();

    shell::Access_interface & shell()                 { return _shell; }
    const QString &           path_to_file()    const { return _path_to_file; }
    int                       version()         const { return _version; }
    const CodeEditParameters & params()         const { return _edit_params; }
    const QList<QString> &    lexis_symbols()   const { return _lexis_symbols; }
    const QVector<shell::DocumentSymbol> & symbols() const { return _symbols; }
    const QVector<shell::CompletionItem> & completions() const { return _completions; }
    const CodeEdit * current_editor() const { return _current_editor; }
    void setCurrentEditor(CodeEdit * editor);
    void forceCompletion();

public:
    // shell::ViewAdaptor_interface
    virtual std::shared_ptr<shell::DocumentAdaptor_interface> document_adaptor() override { return _document_adaptor; }
    virtual QWidget * document_widget() override;
    virtual shell::Document_plugin * plugin() override;

    virtual void readyToWork(QWidget * widget) override;

    virtual QWidget * copyWidget() override;

    virtual QString loadFile(const QString &file_name) override;
    virtual void setReadOnly() override;
    virtual void print(QPrinter * printer) override;

    virtual void cutFromDocument() override { _current_editor->cut(); }
    virtual void copyFromDocument() override { _current_editor->copy(); }
    virtual void pasteToDocument() override { _current_editor->paste(); }
    virtual bool hasSelection() override { return _current_editor->textCursor().hasSelection(); }
    virtual bool hasUndo() override { return _editor->document()->isUndoAvailable(); }
    virtual bool hasRedo() override { return _editor->document()->isRedoAvailable(); }

    virtual void zoomIn() override;
    virtual void zoomOut() override;
    virtual void zoomZero() override;

    virtual QPair<int,int> getLineCol() const override;
    virtual void setLineCol(QPair<int,int> line_col) override;

    virtual bool acceptData(const QJsonObject & ) override 
            { return false; }

    virtual shell::ViewAdaptorLsp_interface * getLspInterface() override 
            { return _edit_params.lsp_support ? this : nullptr; }
    virtual shell::ViewAdaptorFind_interface * getFindInterface() override 
            { return this; }
    virtual shell::AdaptorModeling_interface * getModelingInterface() override 
            { return nullptr; }
    virtual void nearToClose() override;

public:
    // shell::ViewAdaptorLsp_interface:
    virtual int document_version() const override { return _version; }
    virtual void publishDiagnostics(int version, QVector<shell::Diagnostic> & diagnostics, int checksum) override;
    virtual void hover(const void * sender, const QString & kind, const QString & value) override;
    virtual void documentSymbol(QVector<shell::DocumentSymbol> & symbols) override;
    virtual void semanticTokens(std::multimap<int,shell::SemanticToken> & tokens, int checksum) override;
    virtual void completionItems(const void * sender, QVector<shell::CompletionItem> & completions) override;

public:
    // shell::ViewAdaptorFind_interface:
    virtual QString getSampleTextToFind() const override;
    virtual bool find(const QString & str, QTextDocument::FindFlags options) override;
    virtual bool replace(const QString & what, const QString & to, QTextDocument::FindFlags options, bool all) override;

public slots:
    void markModification();

signals:
    void gotPublishDiagnostics(int version);
    void gotHover(const void * sender, const QString & kind, const QString & value);
    void gotDocumentSymbol();
    void gotSemanticTokens();
    void gotCompletionItems(const void * sender);
    void gotZoom(int size);

protected:
    virtual void timerEvent(QTimerEvent *event) override;

    CodeEditParameters loadEditParameters();
    CodeEditParameters loadEditParameters(std::shared_ptr<simodo::variable::Object> object, 
                                          CodeEditParameters params);
    CodeEditParameters prepareLanguageData(CodeEditParameters params);
    CodeEditParameters checkCapabilities(CodeEditParameters params);
    void sendDidChangeNotification();
};

#endif // ViewAdaptor_H
